﻿using System.IO.Ports;
namespace UHIDLInk
{
    /// <summary>
    /// 端口管理类
    /// </summary>
    public class PortMessenger
    {
        /// <summary>
        /// 构造函数
        /// 串口信息在类初始化时就通过命令行输入设置完毕
        /// </summary>
        internal PortMessenger()
        {
            //读取端口名列表
            string[] portNames = SerialPort.GetPortNames();
            foreach (string str in portNames)
            {
                //输出端口信息
                Console.WriteLine(str.Substring(3));
                try
                {
                    using SerialPort port = new(str);
                    port.Open();
                    //Console.WriteLine($"端口名称: {str}，波特率: {port.BaudRate}，数据字节数: {port.DataBits}，校验: {port.Parity}，停止位: {port.StopBits}");
                    port.Close(); // 关闭串口
                }
                catch (Exception ex)
                {
                    Console.WriteLine("e");
                    //Console.WriteLine($"访问接口{str}错误: {ex.Message}，无法显示端口详情");
                }
            }

            //交互
            Console.WriteLine(":");
            //Console.WriteLine("请输入要连接的端口名称，推荐使用COM后数字较大的接口");
            do
            {
                //读取端口名
                portName = Console.ReadLine() ?? "";
            }
            //判断输入正确
            while (!(portNames).Contains(portName));
            //初始化端口
            SP = new SerialPort(portName, 9600, Parity.None, 8, StopBits.One)
            {
                //设置不握手
                Handshake = Handshake.None
            };
        }

        /// <summary>
        /// 端口名
        /// </summary>
        private readonly string portName;

        /// <summary>
        /// 端口API类，来自System.IO.Ports;
        /// </summary>
        private readonly SerialPort SP;

        /// <summary>
        /// 逐个按键控制
        /// </summary>
        public void ControlKeybyKey()
        {
            //开启串口
            SP.Open();
            //Console.WriteLine("现在可以用键盘输入字符，按住Shift + Esc退出：");
            ConsoleKeyInfo CKI;
            FramePackageCMDBuilder builder = new();

            //自动判断鼠标移动方向，x、y、s的值均在0-127之间
            void moveMouse(ConsoleKey k, bool L, bool R, bool M, int x, int y, int s)
            {
                if (k == ConsoleKey.LeftArrow)
                {
                    BUILDMouseFP(L, R, M, -x, 0, s, builder);
                }
                else if (k == ConsoleKey.DownArrow)
                {
                    BUILDMouseFP(L, R, M, 0, y, s, builder);
                }
                else if (k == ConsoleKey.RightArrow)
                {
                    BUILDMouseFP(L, R, M, x, 0, s, builder);
                }
                else if (k == ConsoleKey.UpArrow)
                {
                    BUILDMouseFP(L, R, M, 0, -y, s, builder);
                }
            }

            //点击鼠标
            void clickMouse(ConsoleKey k, bool L, bool R, bool M, int x, int y, int s)
            {
                if (k == ConsoleKey.LeftArrow)
                {
                    BUILDMouseFP(true, R, M, x, y, s, builder);
                }
                else if (k == ConsoleKey.RightArrow)
                {
                    BUILDMouseFP(L, true, M, x, y, s, builder);
                }
            }


            do
            {
                CKI = Console.ReadKey();
                if (CKI.Key != ConsoleKey.LeftArrow && CKI.Key != ConsoleKey.RightArrow && CKI.Key != ConsoleKey.UpArrow && CKI.Key != ConsoleKey.DownArrow)
                {
                    BUILDKeyFP(CKI, builder);
                }
                else
                {
                    switch (CKI.Modifiers)
                    {
                        case ConsoleModifiers.Control:
                            // 控制键 + 方向键移动鼠标
                            moveMouse(CKI.Key, false, false, false, 25, 25, 0);
                            break;
                        case ConsoleModifiers.Shift:
                            // Shift键 + 方向键移动鼠标
                            moveMouse(CKI.Key, false, false, false, 5, 5, 0);
                            break;
                        case ConsoleModifiers.Shift | ConsoleModifiers.Control:
                            // 控制键 + Shift键 + 方向键点击鼠标
                            clickMouse(CKI.Key, false, false, false, -1, -1, 0);
                            break;
                        default:
                            // 方向键
                            BUILDKeyFP(CKI, builder);
                            break;
                    }
                }
            }
            //按下shift+esc退出
            while (CKI.Key != ConsoleKey.Escape || (CKI.Modifiers & ConsoleModifiers.Shift) != ConsoleModifiers.Shift);
            //关闭端口
            if (!this.SP.IsOpen)
                SP.Close();
        }

        /// <summary>
        /// 逐个按键控制鼠标
        /// </summary>
        /// <param name="L">左键</param>
        /// <param name="M">中键</param>
        /// <param name="R">右键</param>
        /// <param name="x">横向</param>
        /// <param name="y">纵向</param>
        /// <param name="builder">构建工具类</param>
        private void BUILDMouseFP(bool L, bool R, bool M, int x, int y, int scroll, FramePackageCMDBuilder builder)
        {
            // 构建鼠标移动数据包
            var FP = FramePackageCMDBuilder.BuildMouseMotion(L, R, M, x, y, scroll);
            byte[] fullPKG = FP.FullPackage;
            // 构建鼠标停止数据包
            byte[] fullPKG2 = FramePackageCMDBuilder.BuildMouseStop(FP).FullPackage;
            //Console.WriteLine($"发送{Utility.ByteArrayToHexString(fullPKG)}");
            // 发送数据包
            SendKeyGetResult(fullPKG);
            SendKeyGetResult(fullPKG2);
            //Console.WriteLine($"发送{Utility.ByteArrayToHexString(fullPKG2)}");
        }

        /// <summary>
        /// 建立键盘数据包并发送
        /// </summary>
        /// <param name="CKI">命令行按键信息</param>
        /// <param name="builder">构建工具类</param>
        private void BUILDKeyFP(ConsoleKeyInfo CKI, FramePackageCMDBuilder builder)
        {
            // 构建按键按下数据包
            var FP = FramePackageCMDBuilder.BuildKeyDownFPFromCKI(CKI);
            byte[] fullPKG = FP.FullPackage;
            // 构建按键抬起数据包
            byte[] fullPKG2 = FramePackageCMDBuilder.BuildKeyUpFromFPFromFP(FP).FullPackage;
            //Console.WriteLine($"发送：{Utility.ByteArrayToHexString(fullPKG)}");
            // 发送数据包
            SendKeyGetResult(fullPKG);
            SendKeyGetResult(fullPKG2);
            //Console.WriteLine($"发送{Utility.ByteArrayToHexString(fullPKG2)}");
        }

        /// <summary>
        /// 发送串口数据
        /// </summary>
        /// <param name="fullPKG">要发送的字节数组</param>
        public string SendKeyGetResult(byte[] fullPKG)
        {
            try
            {
                FramePackageCMDBuilder builder = new();
                //发送数组
                SP.Write(fullPKG, 0, fullPKG.Length);
                //读取当前返回值
                string ReturnStr = SP.ReadExisting();
                //输出
                //Console.WriteLine($"端口返回：{BitConverter.ToString(Encoding.Default.GetBytes(ReturnStr)).Replace("-", " ")}");
                return ReturnStr;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            return string.Empty;
        }
    }
}
